#ifndef _ITEXTBLOCK_H_
#define _ITEXTBLOCK_H_

#include <BPainter>
#include <BTextFormat>
#include "ICodeCell.h"

namespace BWE
{
	class ITextBlock
	{
	public:
		ITextBlock();
		ITextBlock(const ITextBlock& other);
		~ITextBlock();

		inline bool isdirty() const
		{
			return dirtyFont || dirtyCells;
		}

		inline void setFont(const BFont* font)
		{
			if (_font != font)
			{
				_font = font;
			}
			dirtyFont = true;
			dirtyCells = true;
		}
		inline const BFont* font() const
		{
			return _font;
		}

		inline void clear()
		{
			text.clear();
			reset();
		}
		inline bool empty() const
		{
			return cells.empty();
		}
		inline int tail() const
		{
			if (cells.last().code == '\n')
				return cells.size() - 1;
			return cells.size();
		}

		void reset();
		void reset(const BString& text);
		void append(const BString& text);
		bool remove(int pos, int count = 1);
		inline void flushText()
		{
			text.reset();
			for (int i = 0; i < cells.size(); i++)
			{
				text.append(cells[i].code);
			}
		}

		BString substr(int pos, int count) const;
		BString selection() const;

		bool selectWord();
		bool removeSelection();

		inline bool seekHead()
		{
			if (inputIndex != 0 || inputCount != 0)
			{
				inputIndex = 0;
				inputCount = 0;
				return true;
			}
			return false;
		}
		inline bool seekPoint(const BPoint& point)
		{
			int index = indexAt(point);
			if (inputIndex != index || inputCount != 0)
			{
				inputIndex = index;
				inputCount = 0;
				return true;
			}
			return false;
		}
		inline bool seekTail()
		{
			int tail = cells.size();
			if (cells.last().code == '\n')
				tail = cells.size() - 1;
			if (inputIndex != tail || inputCount != 0)
			{
				inputIndex = tail;
				inputCount = 0;
				return true;
			}
			return false;
		}

		inline int seekPrevCode()
		{
			inputIndex--;
			inputCount = 0;
			return inputIndex;
		}
		inline int seekNextCode()
		{
			inputIndex++;
			inputCount = 0;
			return inputIndex;
		}
		inline int seekPrevWord()
		{
			inputCount = 0;
			bool found = false;
			int begin = inputIndex;
			while (--begin > 0)
			{
				const BCode& code = cells[begin].code;
				if (code > 255 || !code.isSpace())
				{
					found = true;
					continue;
				}
				if (found && code.isSpace())
				{
					begin++;
					break;
				}
			}
			inputIndex = begin;
			return inputIndex;
		}
		inline int seekNextWord()
		{
			int size = cells.size();
			int begin = inputIndex;
			while (begin < size)
			{
				const BCode& code = cells[begin].code;
				if (code < 255)
				{
					if (code.isSpace())
						break;
				}
				begin++;
			}
			while (begin < size)
			{
				const BCode& code = cells[begin].code;
				if (code < 255)
				{
					if (!code.isSpace())
						break;
				}
				begin++;
			}
			inputIndex = begin;
			return inputIndex;
		}

		int indexAt(const BPoint& pos) const;
		int wordWidth(int index) const;

		void adjust(int pageWidth);
		void paint(BPainter& painter);

	public:
		bool				visible;
		bool				wordWrap;
		BRect				rect;
		Align				align;
		BRange				range;
		BString				text;
		BArray<CodeCell>	cells;
		bool				dirtyCells;
		bool				dirtyFont;
		int					rowHeight;
		int					inputIndex;
		int					inputCount;
		BHolder<const BFont>	_font;
		BHolder<BTextFormat>	textFormat;
	};

}

#endif